package me.zhengjie.common.utils

import me.zhengjie.logging.slf4j.*
import org.springframework.beans.BeansException
import org.springframework.beans.factory.DisposableBean
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.core.env.Environment
import org.springframework.stereotype.Service
import java.util.*

/**
 * @author Jie
 * @date 2019-01-07
 */

class SpringContextHolder : ApplicationContextAware, DisposableBean {
    override fun destroy() {
        clearHolder()
    }

    @Throws(BeansException::class)
    override fun setApplicationContext(applicationContext: ApplicationContext) {
        if (Companion.applicationContext != null) {
            logDebug("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + Companion.applicationContext)
        }
        Companion.applicationContext = applicationContext
    }

    companion object {
        private var applicationContext: ApplicationContext? = null
        private val CALL_BACKS: MutableList<CallBack> = ArrayList()
        private var addCallback = true

        /**
         * 针对 某些初始化方法，在SpringContextHolder 未初始化时 提交回调方法。
         * 在SpringContextHolder 初始化后，进行回调使用
         *
         * @param callBack 回调函数
         */
        @Synchronized
        fun addCallBacks(callBack: CallBack) {
            if (addCallback) {
                CALL_BACKS.add(callBack)
            } else {
                logError("CallBack：{${callBack.callBackName}} 已无法添加！立即执行")
                callBack.executor()
            }
        }
        /**
         * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
         */
        fun <T> getBean(name: String?): T {
            assertContextInjected()
            return applicationContext!!.getBean(name!!) as T
        }

        /**
         * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
         */
        fun <T> getBean(requiredType: Class<T>): T {
            assertContextInjected()
            return applicationContext!!.getBean(requiredType)
        }


        /**
         * 获取SpringBoot 配置信息
         *
         * @param property     属性key
         * @param defaultValue 默认值
         * @param requiredType 返回类型
         * @return /
         */
        fun <T> getProperties(property: String?, defaultValue: T, requiredType: Class<T>?): T {
            var result = defaultValue
            try {
                result = getBean(Environment::class.java).getProperty(
                    property!!, requiredType!!
                )!!
            } catch (ignored: Exception) {
            }
            return result
        }

        /**
         * 获取SpringBoot 配置信息
         *
         * @param property 属性key
         * @return /
         */
        fun getProperties(property: String?): String {
            return getProperties<String>(property, "", String::class.java)
        }

        /**
         * 获取SpringBoot 配置信息
         *
         * @param property     属性key
         * @param requiredType 返回类型
         * @return /
         */
        fun <T> getProperties(property: String?, requiredType: Class<T?>?): T? {
            return getProperties(property, null, requiredType)
        }
        /**
         * 检查ApplicationContext不为空.
         */
        private fun assertContextInjected() {
            checkNotNull(applicationContext) {
                "applicaitonContext属性未注入, 请在applicationContext" +
                        ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder."
            }
        }

        // 国际化使用
        fun getMessage(key: String?): String {
            return applicationContext!!.getMessage(key!!, null, Locale.getDefault())
        }

        val activeProfile: String
            /// 获取当前环境
            get() = applicationContext!!.environment.activeProfiles[0]

        /**
         * 清除SpringContextHolder中的ApplicationContext为Null.
         */
        private fun clearHolder() {
            logDebug(
                "清除SpringContextHolder中的ApplicationContext:"
                        + applicationContext
            )
            applicationContext = null
        }


        fun destroy() {
            clearHolder()
        }

        @Throws(BeansException::class)
        fun setApplicationContext(applicationContext: ApplicationContext?) {
            if (SpringContextHolder.applicationContext != null) {
               logError("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext)
            }
            SpringContextHolder.applicationContext = applicationContext
            if (addCallback) {
                for (callBack in CALL_BACKS) {
                    callBack.executor()
                }
                CALL_BACKS.clear()
            }
            addCallback = false
        }

        /**
         * 获取 @Service 的所有 bean 名称
         * @return /
         */
        fun getAllServiceBeanName(): List<String>? {
            return ArrayList(
                Arrays.asList(
                    *applicationContext!!
                        .getBeanNamesForAnnotation(Service::class.java)
                )
            )
        }
    }
}